/*
 * Copyright (c) 2008-2009 Ravenhearte Design
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'Ravenhearte Design' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.ravenhearte.hardboild.gui;

import java.util.LinkedList;
import java.util.ListIterator;

import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.Spatial.CullHint;
import com.jme.math.Vector3f;

/**
 * <code>Container</code> is <code>Element</code>'s habitually responsible older brother,
 * he keeps all the other littler <code>Element</code>s in line.
 * 
 * @author Jesse Whitworth
 * @version $Revision$
 */
public class Container extends Element{
	/**
	 * 
	 */
	private Node node, listNode;
	private static int backgroundCount = 0;
	private int cells, length, currentCell;
	private LinkedList<Element> elements;
	private boolean scrollable, horizontalLayout, managedLayout;
	private Button[] buttons;
	
	
	public Container(String name, int x, int y, int width, int height) {
		super(name);
		
		node = new Node(name + "'s Node");
		listNode = new Node(name + "'s List");
		node.attachChild(listNode);
		
		setLocation(x, y);
		setSize(width, height);
		
		cells = currentCell = 0;
		
		elements = new LinkedList<Element>();
		
		scrollable = false;
		horizontalLayout = false;
		managedLayout = true;
	}
	
	public boolean isScrollable() {
		return scrollable;
	}
	
	public void toggleScrollable() {
		scrollable = !scrollable;
		if(scrollable) {
			initializeScrollBar();
		}
	}
	
	public void toggleManagedLayout() {
		managedLayout = !managedLayout;
	}
	
	public void addElement(Element element) {		
		/*if (element.getWidth() > getWidth() ||
			element.getHeight() > getHeight()) {
			
			return;
		}*/
		
		cells++;
		
		elements.add(element);
		listNode.attachChild(element.getSpatial());
		
		calculateVisibility();
	}
	
	public void deleteElement(Element element) {
		cells--;
		
		elements.remove(element.getName());
		listNode.detachChild(element.getSpatial());
		
		calculateVisibility();
	}
	
	private void calculateVisibility() {
		if(!managedLayout) {
			return;
		}
		
		ListIterator<Element> it = elements.listIterator();
		while(it.hasNext()) {
			int which = it.nextIndex();
			Element element = it.next();
			
			if(horizontalLayout) {
				if (cells == 1) {
					length = element.getWidth();
				}
				
				int eX = (which * length) - (currentCell * length);
				element.setLocation(eX, 0);
				
				if (eX + length > getWidth()) {
					element.getSpatial().setCullHint(CullHint.Always);
				}
			}
			else {
				if (cells == 1) {
					length = element.getHeight();
				}

				int eX = 0;
				int eY = 10 + (which * length) - (currentCell * length);

				switch (element.getAlignment()) {
				case LEFT:
					eX = 10;
					break;
				case RIGHT:
					eX = getWidth() - 10;
					break;
				case CENTERED:
					eX = getWidth() / 2;
					break;
				}
				
				element.setLocation(eX, eY);
				
				if (eY + length > getHeight()) {
					element.getSpatial().setCullHint(CullHint.Always);
				}
			}
		}
	}
	
	public Element getCurrentCell() {
		if(!managedLayout) {
			return null;
		}
		
		ListIterator<Element> it = elements.listIterator();
		while(it.hasNext()) {
			Element e = it.next();
			if(e.getSpatial().getCullHint() != CullHint.Always) {
				return e;
			}
		}
		
		return null;
	}
	
	public void setBackground(String filename, int x, int y) {
		ImageElement background = new ImageElement(getName() + "'s Background",
				getWidth(), getHeight());
		background.setTexture(filename, x, y);
		background.getSpatial().setZOrder(200 - backgroundCount++);
		node.attachChild(background.getSpatial());
	}

	/**
	 * This sets a bordered background on the container. The current incarnation
	 * assumes the image is a 20x20 subset of some larger image, that the corners
	 * comprise 6px squares and that the edges and inside should be stretched to
	 * fit the size of the container.
	 * @param filename the filename of the image.
	 * @param x the x-offset where the bordered 20x20 image is in the larger file.
	 * @param y the y-offset where the bordered 20x20 image is in the larger file.
	 */
	public void setBorderedBackground(String filename, int x, int y) {
		int cornerSide = 6;
		int farEdge = 20 - cornerSide;
		int edgeLength = 20 - (2*cornerSide);
		int zOrder = (200 - backgroundCount++);

		//Top Left Corner
		ImageElement temp = new ImageElement(getName() + "'s Background",
				cornerSide, cornerSide);
		temp.setTexture(filename, x, y);
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(0, 0);
		node.attachChild(temp.getSpatial());
		
		//Top Right Corner
		temp = new ImageElement(getName() + "'s Background",
				cornerSide, cornerSide);
		temp.setTexture(filename, x+farEdge, y);
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(getWidth()-cornerSide, 0);
		node.attachChild(temp.getSpatial());
		
		//Bottom Left Corner
		temp = new ImageElement(getName() + "'s Background",
				cornerSide, cornerSide);
		temp.setTexture(filename, x, y+farEdge);
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(0, getHeight()-cornerSide);
		node.attachChild(temp.getSpatial());
		
		//Bottom Right Corner
		temp = new ImageElement(getName() + "'s Background",
				cornerSide, cornerSide);
		temp.setTexture(filename, x+farEdge, y+farEdge);
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(getWidth()-cornerSide,	getHeight()-cornerSide);
		node.attachChild(temp.getSpatial());
		
		//Top Edge
		temp = new ImageElement(getName() + "'s Background",
				edgeLength, cornerSide);
		temp.setTexture(filename, x+cornerSide, y);
		temp.setSize(getWidth()-(2*cornerSide), cornerSide);
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(cornerSide, 0);
		node.attachChild(temp.getSpatial());
		
		//Bottom Edge
		temp = new ImageElement(getName() + "'s Background",
				edgeLength, cornerSide);
		temp.setTexture(filename, x+cornerSide, y+farEdge);
		temp.setSize(getWidth()-(2*cornerSide), cornerSide);
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(cornerSide, getHeight()-cornerSide);
		node.attachChild(temp.getSpatial());
		
		//Left Edge
		temp = new ImageElement(getName() + "'s Background",
				cornerSide, edgeLength);
		temp.setTexture(filename, x, y+cornerSide);
		temp.setSize(cornerSide, getHeight()-(2*cornerSide));
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(0, cornerSide);
		node.attachChild(temp.getSpatial());
		
		//Right Edge
		temp = new ImageElement(getName() + "'s Background",
				cornerSide, edgeLength);
		temp.setTexture(filename, x+farEdge, y+cornerSide);
		temp.setSize(cornerSide, getHeight()-(2*cornerSide));
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(getWidth()-cornerSide, cornerSide);
		node.attachChild(temp.getSpatial());
		
		//Creamy Filling
		temp = new ImageElement(getName() + "'s Background",
				edgeLength, edgeLength);
		temp.setTexture(filename, x+cornerSide, y+cornerSide);
		temp.setSize(getWidth()-(2*cornerSide), getHeight()-(2*cornerSide));
		temp.getSpatial().setZOrder(zOrder);
		temp.setLocation(cornerSide, cornerSide);
		node.attachChild(temp.getSpatial());
	}
	
	private void initializeScrollBar() {
		TransparentImageButton temp1 = new TransparentImageButton(getName() + "'s Scroll Up", 20, 20);
		temp1.setTexture("titlescreen.png", 100, 768);
		temp1.setState("MouseOut", 100, 768);
		temp1.setState("MouseOver", 100, 788);
		temp1.setState("MouseClick", 100, 768);
		temp1.getSpatial().setZOrder(-5);
		temp1.setLocation(getWidth()-20, 10);
		
		TransparentImageButton temp2 = new TransparentImageButton(getName() + "'s Scroll Down", 20, 20);
		temp2.setTexture("titlescreen.png", 120, 768);
		temp2.setState("MouseOut", 120, 768);
		temp2.setState("MouseOver", 120, 788);
		temp2.setState("MouseClick", 120, 768);
		temp2.getSpatial().setZOrder(-5);
		temp2.setLocation(getWidth()-20, getHeight()-30);

		node.attachChild(temp1.getSpatial());
		node.attachChild(temp2.getSpatial());
		
		buttons = new Button[]{temp1, temp2};
	}
	
	public void scrollUp() {
		if(horizontalLayout) {
			
		}
		else {
			if((cells * length) < getHeight()) {
				return;
			}
			else if(((cells * length) - (currentCell * length)) > getHeight()) {
				return;
			}
			else {
				Vector3f loc = listNode.getLocalTranslation();
				loc.y -= length;
				listNode.setLocalTranslation(loc);
				
				currentCell--;
				
				Spatial child = listNode.getChild(currentCell);
				child.setCullHint(CullHint.Never);
				
				child = listNode.getChild(currentCell + getHeight() / length);
				child.setCullHint(CullHint.Always);
			}
		}
	}
	
	public void scrollDown() {
		if(horizontalLayout) {
			
		}
		else {
			if((cells * length) < getHeight()) {
				return;
			}
			else if(((cells * length) - (currentCell * length)) < getHeight()) {
				return;
			}
			else {
				Vector3f loc = listNode.getLocalTranslation();
				loc.y += length;
				listNode.setLocalTranslation(loc);
				
				Spatial child = listNode.getChild(currentCell);
				child.setCullHint(CullHint.Always);
				
				child = listNode.getChild(currentCell + getHeight() / length);
				child.setCullHint(CullHint.Never);
				
				currentCell++;
			}
		}
	}

	public Spatial getSpatial() {
		return node;
	}
	
	public Button[] getButtons() {
		return buttons;
	}

	protected void resize(int width, int height) {
		// Don't.
	}

	public void setLocation(int x, int y) {
		int lowerX, lowerY;
		lowerX = 0;
		lowerY = y;
		switch (getAlignment()) {
		case LEFT:
			lowerX = x;
			break;
		case RIGHT:
			lowerX = x - getWidth();
			break;
		case CENTERED:
			lowerX = x - (getWidth() / 2);
			break;
		}
		int xDiff = lowerX - getLowerX();
		int yDiff = -(lowerY - getLowerY());
		
		
		Vector3f nodeLoc = node.getLocalTranslation();
		
		nodeLoc.addLocal(xDiff, yDiff, 0);
		node.setLocalTranslation(nodeLoc);
		
		setLowerX(lowerX);
		setLowerY(lowerY);
	}
}